#pragma once

#include "exports.hpp"
#include "scheduler.hpp"
#include "thread.hpp"




namespace services
{
	/**
	 * The scheduler implements the asynchronous execution of tasks on one or more threads.
	 *
	 * The usage is very simple:
	 * Simply pass a functor into scheduler::execute and keep the remaining future object.
	 * You may check the future object if it's ready by calling future::ready() and future::value()
	 * when it is. This function will either return the value or throw the exact (or a copy of the)
	 * exception that has been thrown by the original functor.
	 */
	class SERVICES_API threadpool_scheduler
		: public scheduler
	{
	public:

		SHARED(threadpool_scheduler);

		threadpool_scheduler(boost::shared_ptr<const provider>);
		virtual ~threadpool_scheduler();



		/**
		 * @returns a list of all currently running tasks
		 */
		std::vector<task::const_ptr> activeTasks();

		/**
		 * Executes the given task by adding it to a worker thread.
		 * The thread will then decide when to execute the task.
		 */
		void executeTask(task::ptr t);

	private:

		/**
		 * Adds the given task to this scheduler.
		 * Adding a task from within a task that is executed by this
		 * scheduler is undefined.
		 */
		void add(task::ptr t);

		/**
		 * Removes the given task from this scheduler.
		 * Blocks until the task finished executing (if it being executed) and removes it.
		 *
		 * Removing a task from within a task that is executed by this scheduler
		 * is undefined.
		 */
		void remove(task::ptr t);

		/**
		 * This function is executed as a task and is responsible
		 * for updating the scheduler.
		 */
		void task_run();

	private:

		typedef std::vector<thread::ptr>   threads;
		typedef boost::shared_mutex                  mutex;
		typedef boost::shared_lock<mutex>            read_lock;
		typedef boost::unique_lock<mutex>            write_lock;

		threads   m_threads;
		mutex     m_mutex;
	};
	///////////////////////////////////////////////////////////////////////////////////////////////
}
///////////////////////////////////////////////////////////////////////////////////////////////////
